package com.feeyo.groundservice.http.core

import android.os.Environment
import com.feeyo.groundservice.base_util.FyLog
import com.feeyo.groundservice.http.base.BusinessExceptionHandler
import com.feeyo.groundservice.http.beans.BusinessBaseResponse
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import okhttp3.Cache
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import java.io.File
import java.util.concurrent.TimeUnit


/**
 * 作者：QLH on 2018-12-01
 * 描述：管理Retrofit
 */
internal object RetrofitUtils {

    //超时时间 10s
    private val DEFAULT_TIME_OUT = 10L
    private val DEFAULT_READ_TIME_OUT = 10L
    private val DEFAULT_WRITE_TIME_OUT = 10L

    private var baseUrl: String = ""
    private var builder: OkHttpClient.Builder? = null

    //全局的错误处理函数
    private var businessExceptionHandler: BusinessExceptionHandler? = null

    //最基础的外层bean字段映射：code msg data
    private var baseBean: IBaseBean? = null

    private var businessBaseResponseCls: Class<BusinessBaseResponse> =
        BusinessBaseResponse::class.java

    //允许data返回null
    private var allowDataIsNull: Boolean = false

    private val moshi by lazy {
        Moshi.Builder()
            .add(MoshiResultTypeAdapterFactory(baseBean))
            .add(KotlinJsonAdapterFactory())
            .build()
    }

    //日志开关
    private var logEnable = true

    //全局唯一实例,统一的okhttpBuilder，也可以自己扩展定义
    private val okhttpBuilder by lazy {
        //需要权限
        //OkHttp的缓存只能用于Get请求。OkHttp的Cache类中，对于GET以外的请求，
        // 都返回null。源码中也做出了解释：不允许Get以外的请求，
        // 从技术上是允许post请求的。但是他的复杂度很高，实用性太低
        val cacheFile = File(Environment.getExternalStorageDirectory(), "okHttpCache")
        if (!cacheFile.exists()) {
            cacheFile.mkdirs()
        }
        val cache = Cache(cacheFile, (1024 * 1024 * 100).toLong())//100M

        OkHttpClient.Builder()
            .readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS)
            .connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
            .writeTimeout(DEFAULT_WRITE_TIME_OUT, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
            .apply {
                FyLog.e("RetrofitUtils", "okhhttp日志开关:$logEnable")
                if (logEnable) {//Http日志开关
                    addInterceptor(HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
                        override fun log(message: String) {
                            FyLog.json("RetrofitUtils", message)
                        }
                    }).apply {
                        level = HttpLoggingInterceptor.Level.BODY
                    })
                }
            }
            .cache(cache)

    }

    /**
     * @param baseUrl  基础域名
     * @param baseBean 接口单独定制的BaseBean
     * @param allowDataIsNull 是否允许data返回null，默认不允许为空
     * @param businessBaseResponseCls 未被服务器处理过的响应错误：4xx,5xxx ...，一般用不上
     */
    fun getRetrofitBuilder(
        baseUrl: String? = null,
        baseBean: IBaseBean? = null,
        allowDataIsNull: Boolean? = null,
        businessBaseResponseCls: Class<BusinessBaseResponse>? = null
    ): Retrofit.Builder {
        val okHttpClientBuilder = builder ?: okhttpBuilder
        //如果有特殊定制的就临时使用，否则使用全局的
        val tempMoshi = baseBean?.let {
            Moshi.Builder()
                .add(MoshiResultTypeAdapterFactory(it))
                .add(KotlinJsonAdapterFactory())
                .build()
        } ?: moshi

        val dataIsNull = allowDataIsNull ?: RetrofitUtils.allowDataIsNull
        val businessBaseResponseClass =
            businessBaseResponseCls ?: RetrofitUtils.businessBaseResponseCls

        return Retrofit.Builder()
            .client(okHttpClientBuilder.build())
            .addConverterFactory(MoshiConverterFactory.create(tempMoshi))
            .addCallAdapterFactory(
                HttpResponseCallAdapterFactory(
                    businessExceptionHandler,
                    dataIsNull,
                    businessBaseResponseClass
                )
            )
            .baseUrl(baseUrl ?: RetrofitUtils.baseUrl)
    }

    /**获取okhttpBuild，在需要扩充配置的时候进行设置**/
    fun getOkhttpClientBuilder(): OkHttpClient.Builder {
        return builder ?: okhttpBuilder
    }

    /**设置BaseURL**/
    fun setBaseUrl(url: String) {
        baseUrl = url
    }

    /**设置全局异常处理对象**/
    fun setBusinessExceptionHandler(globalErrorHandler: BusinessExceptionHandler) {
        businessExceptionHandler = globalErrorHandler
    }

    /**
     * 定义好字段映射关系
     * 如果能映射到code+msg+data 就去重写本方法，否则就空着
     * 然后就要自己判断业务成功code和对应的处理之类的了
     *
     */
    fun setBaseBean(baseBean: IBaseBean) {
        RetrofitUtils.baseBean = baseBean
    }

    /**设置OkHttpBuilder**/
    fun setOkhttpClientBuilder(builder: OkHttpClient.Builder) {
        RetrofitUtils.builder = builder
    }

    /**是否允许data返回null**/
    fun setAllowDataIsNull(allowDataIsNull: Boolean) {
        RetrofitUtils.allowDataIsNull = allowDataIsNull
    }

    /****/

    fun setBusinessBaseResponseClass(businessBaseResponseCls: Class<BusinessBaseResponse>) {
        RetrofitUtils.businessBaseResponseCls = businessBaseResponseCls
    }

    /**
     * @return true:设置了 false:没有设置
     * **/
    fun isSetBaseUrl(): Boolean = baseUrl.isNotEmpty()

    /**
     * 基础LOG显示
     *
     * @param logEnable
     */
    fun setLogEnable(logEnable: Boolean) {
        RetrofitUtils.logEnable = logEnable
    }

}
